﻿using ServerCommon.Log;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using uid_t = System.Int64;
namespace ServerCommon.Net
{
    public class NetNodeReconnect
    {
        public static readonly NetNodeReconnect Instance = new Lazy<NetNodeReconnect>(() => new NetNodeReconnect(), true).Value;
        private static LogHelper log = LogHelper.GetLogger(typeof(NetNodeReconnect));

        private Dictionary<Guid, NetClient> _dicReconnect;
        private Dictionary<uid_t, NetClient> _dicReconnectNodeIds;
        private Thread _reconnectThread;
        private bool _reconnectThreadStop;

        public NetNodeReconnect()
        {
            _dicReconnect = new Dictionary<Guid, NetClient>();
            _dicReconnectNodeIds = new Dictionary<uid_t, NetClient>();
            _reconnectThread = new Thread(ReconnectThread);
            _reconnectThreadStop = false;
        }

        public void Init()
        {
            _reconnectThread.Start();
        }

        public void Release()
        {
            _reconnectThreadStop = true;
            if (_reconnectThread.ThreadState == ThreadState.Running)
            {
                _reconnectThread.Join();
            }
        }

        public void StartReconnect(NetClient netNode)
        {
            lock (_dicReconnect)
            {
                if (!_dicReconnect.ContainsKey(netNode.HashCode))
                {
                    _dicReconnect.Add(netNode.HashCode, netNode);
                }

                if (netNode.NodeId != 0)
                {
                    if (_dicReconnectNodeIds.ContainsKey(netNode.NodeId))
                    {
                        log.WarnFormat("startReconnect nodeId duplicate : {0}", netNode.NodeId);
                    }
                    else
                    {
                        _dicReconnectNodeIds.Add(netNode.NodeId, netNode);
                    }
                }

            }
        }
        /// <summary>
        /// Node作为客户端发起连接，当已经连接上，或者主动要求不要连接的时候，停止自动重连
        /// </summary>
        /// <param name="netNode"></param>
        public void StopReconnect(NetClient netNode)
        {
            lock (_dicReconnect)
            {
                _dicReconnect.Remove(netNode.HashCode);
                _dicReconnectNodeIds.Remove(netNode.NodeId);
            }

        }
        /// <summary>
        /// 当Node（Game）没有收到中心服发过来的其它进程（Gateway）stop的通知，那么当中心服下次通知其它进程已经启动（Gateway）
        /// 那么存在两个对其它进程的连接 ：断线重连和主线程的主动链接，所以需要在主线程收到通知的时候，停止断线重连线程的连接
        /// </summary>
        /// <param name="nodeId"></param>
        public void StopReconnect(long nodeId)
        {
            lock (_dicReconnect)
            {
                NetClient netNode = null;
                if (_dicReconnectNodeIds.TryGetValue(nodeId, out netNode))
                {
                    _dicReconnect.Remove(netNode.HashCode);

                }
                _dicReconnectNodeIds.Remove(nodeId);
            }
        }
        private void ReconnectThread()
        {
            while (!_reconnectThreadStop)
            {
                lock (_dicReconnect)
                {
                    try
                    {

                        Dictionary<Guid, NetClient>.ValueCollection netNodes = _dicReconnect.Values;
                        foreach (var v in netNodes)
                        {
                            v.Start();
                        }
                        _dicReconnect.Clear();
                    }
                    catch (ThreadAbortException abortEx)
                    {
                        log.WarnFormat("NetNodeManagerFix ReconnectThread abort", abortEx);
                        break;
                    }
                    catch (Exception ex)
                    {
                        log.WarnFormat("NetNodeManagerFix ReconnectThread abort", ex);
                    }
                }
                Thread.Sleep(1000 * 10);
            }
        }
    }
}
